global !p
def list_files():
    files = []
    for f in os.listdir('.'):
        if f.endswith(('.v', '.h', '.cc')) and not f.startswith('.'):
            files.append(f)
    return ' '.join(files)
endglobal

snippet ls "list source files" iw
`!p snip.rv = list_files()`
endsnippet
############################################################################# if
snippet if "if语句" iw
    if (${1}) begin
        ${0}
    end
endsnippet

############################################################################ If/else
snippet ife "if else语句" iw
    if (${1}) begin
        ${2}
    end else begin
        ${3}
    end
endsnippet

snippet eif  "else if语句" iw
    else if (${1}) begin
        ${0}
    end
endsnippet

############################################################################ Case
snippet case "case 语句" iw
case (${1:/* variable */})
    ${2:/* value */}: begin
        ${3}
    end
    default: begin
        ${4}
    end
endcase
endsnippet
########################################################################### Always
snippet al "always 语句" iw
always @(${1:/* sensitive list */}) begin
    ${0}
end
endsnippet

snippet alsys "always 语句,默认时钟和复位" iw
always @(posedge sys_clk or negedge sys_reset_n) 
if(~sys_reset_n) begin
    ${1}
end else begin
    ${0}
end
endsnippet
############################################################################# var
snippet re "reg 定义" iw
reg                         ${1}_r      ;
${0}
endsnippet
############################################向量定义
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet "r(\d+)" "reg 位宽定义" r
reg         [`!p snip.rv = int(match.group(1))-1`:0]            ${1}_r      ;
${0}
endsnippet
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet wi "wire 定义" iw
wire        ${1}        ;
${0}
endsnippet
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet "w(\d+)" "wire 位宽定义" r
wire        [`!p snip.rv = int(match.group(1))-1`:0]            ${1}    ;
${0}
endsnippet

pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet ra  "带always 定义" iw
reg     ${1}_r      ;
always @(posedge sys_clk or negedge sys_reset_n) 
if(~sys_reset_n) begin
    $1_r        <=      1'b0        ;
end else begin
    ${0}
end
endsnippet

pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet "ra(\d+)"  "带always 定义" r
reg     [`!p snip.rv = int(match.group(1))-1`:0]    ${1}_r      ;
always @(posedge sys_clk or negedge sys_reset_n) 
if(~sys_reset_n) begin
    $1_r        <=      `!p snip.rv = int(match.group(1))`'b0        ;
end else begin
    ${0}
end
endsnippet
#################################################################################端口定义
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet inp "input 定义" iw
input           ${1}        ;
${0}
endsnippet
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet out "output 定义" iw
output          ${1}        ;
${0}
endsnippet
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet ino "inout 定义" iw
inout           ${1}        ;
${0}
endsnippet
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet "i(\d+)" "输入位宽定义" r
input       [`!p snip.rv = int(match.group(1))-1`:0]            ${1}   ;
${0}
endsnippet
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet "o(\d+)" "输出位宽定义" r
output      [`!p snip.rv = int(match.group(1))-1`:0]            ${1}   ;
${0}
endsnippet
pre_expand "snip.buffer[snip.line] = ' '*4; snip.cursor.set(snip.line, 4)"
snippet "t(\d+)" "三态位宽定义，_o,_i,_t" r
input       [`!p snip.rv = int(match.group(1))-1`:0]            ${1}_i  ;
output      [`!p snip.rv = int(match.group(1))-1`:0]            $1_o  ;
output                                  $1_t  ;
${0}
endsnippet
################################################################################ module
snippet modsys "模块，带有默认时钟和复位" iw
module ${1:`!p snip.rv = snip.fn.split('.')[0]`} (
        sys_clk         ,
        sys_reset_n     ,
        ${2}
        );


        input   sys_clk         ;
        input   sys_reset_n     ;

        ${0}
    endmodule
endsnippet
## 带 AXI4-Lite接口的模块
snippet modaxi "module axi4-lite" iw
module ${1:`!p snip.rv = snip.fn.split('.')[0]`} (
        S_AXI_ACLK  , S_AXI_ARESETN ,   
        S_AXI_ARADDR, S_AXI_ARPROT  , S_AXI_ARVALID , S_AXI_ARREADY ,
        S_AXI_RDATA , S_AXI_RVALID  , S_AXI_RREADY  , S_AXI_RRESP   ,
        S_AXI_AWADDR, S_AXI_AWPROT  , S_AXI_AWVALID , S_AXI_AWREADY ,
        S_AXI_WDATA , S_AXI_WVALID  , S_AXI_WREADY  , S_AXI_WSTRB   ,
        S_AXI_BRESP , S_AXI_BVALID  , S_AXI_BREADY  ,
        ${2}
        );

    //localparam  AW = ${3:4};        //AXI地址总线宽度
    //AXI4-Lite 接口,8个32位寄存器
    input               S_AXI_ACLK              ;
    input               S_AXI_ARESETN           ;
    
    input   [`!p snip.rv = int(t[3])-1`:0]    S_AXI_ARADDR            ;
    input   [2:0]       S_AXI_ARPROT            ;
    input               S_AXI_ARVALID           ;
    output              S_AXI_ARREADY           ;
    
    output  [31:0]      S_AXI_RDATA             ;
    output              S_AXI_RVALID            ;
    input               S_AXI_RREADY            ;
    output  [1:0]       S_AXI_RRESP             ;
    
    input   [`!p snip.rv = int(t[3])-1`:0]    S_AXI_AWADDR            ;
    input   [2:0]       S_AXI_AWPROT            ;
    input               S_AXI_AWVALID           ;
    output              S_AXI_AWREADY           ;
    
    input   [31:0]      S_AXI_WDATA             ;
    input               S_AXI_WVALID            ;
    output              S_AXI_WREADY            ;
    input   [3:0]       S_AXI_WSTRB             ;
    
    output  [1:0]       S_AXI_BRESP             ;
    output              S_AXI_BVALID            ;
    input               S_AXI_BREADY            ;

    //读地址通道
    reg     [`!p snip.rv = int(t[3])-1`:0]    raddr_r                 ;   //地址寄存器
    reg                 axi_arready             ;  // S_AXI_ARREADY
    always @(posedge S_AXI_ACLK)
    if(~S_AXI_ARESETN) 
        raddr_r <= $3'h0;    
    else if(S_AXI_ARVALID)
        raddr_r <= S_AXI_ARADDR; 

    always @(posedge S_AXI_ACLK)
    if(~S_AXI_ARESETN)
        axi_arready <= 1'b0;
    else if(S_AXI_ARVALID & ~axi_arready)
        axi_arready <= 1'b1;
    else if(S_AXI_ARVALID & axi_arready)
        axi_arready <= 1'b0;
    assign S_AXI_ARREADY = axi_arready;

    //读数据通道
    reg     [31:0]  axi_rdata       ;
    reg             axi_rvalid      ;
    wire            reg_rd          ;
    assign reg_rd = S_AXI_ARVALID & axi_arready;//当有读地址后，读信号准备好
    assign S_AXI_RRESP = 2'b00; //读数据永远OK
    always @(posedge S_AXI_ACLK)
    if(~S_AXI_ARESETN)
        axi_rvalid <= 1'b0;
    else if(reg_rd)
        axi_rvalid <= 1'b1;
    else if(S_AXI_RREADY & axi_rvalid)
        axi_rvalid <= 1'b0;
    assign S_AXI_RVALID = axi_rvalid;

    always @(posedge S_AXI_ACLK)
    if(~S_AXI_ARESETN)
        axi_rdata   <= 32'h00;
    else case(raddr_r[`!p snip.rv = int(t[3])-1`:2])
        `!p snip.rv = int(t[3])-2`'b000: axi_rdata <= 32'h`date +%Y%m%d` ;    //以当前日期作为ID
        //....
        default: axi_rdata <= 32'h0 ;
    endcase  
    assign S_AXI_RDATA= axi_rdata;

    //写地址通道
    reg     [`!p snip.rv = int(t[3])-1`:0]  waddr_r     ;
    assign S_AXI_AWREADY = 1'b1;    //写数据ready
    always @(posedge S_AXI_ACLK)
    if(~S_AXI_ARESETN)
        waddr_r <= $3'h00;
    else if(S_AXI_AWVALID)
        waddr_r <= S_AXI_AWADDR;

    //写数据通道
    reg             axi_wready  ;
    wire            reg_wr      ;
    assign reg_wr = S_AXI_WVALID & S_AXI_WREADY;
    always @(posedge S_AXI_ACLK)
    if(~S_AXI_ARESETN)
        axi_wready <= 1'b0;
    else if(S_AXI_AWVALID)  //如果写地址有效
        axi_wready <= 1'b1;
    else if(S_AXI_WVALID & axi_wready)
        axi_wready <= 1'b0;

    assign S_AXI_WREADY = axi_wready;

    //写响应通道
    reg         axi_bvalid;
    assign S_AXI_BRESP = 2'b00; //传输无问题
    always @(posedge S_AXI_ACLK)
    if(~S_AXI_ARESETN)
        axi_bvalid  <= 1'b0;
    else if(S_AXI_WVALID & axi_wready)
        axi_bvalid <= 1'b1;
    else if(S_AXI_BREADY & axi_bvalid)
        axi_bvalid <= 1'b0;
    
    assign S_AXI_BVALID = axi_bvalid;

    //demo
    //wire sm_pul_wr;
    //assign sm_pul_wr = reg_wr & (waddr_r[`!p snip.rv = int(t[3])-1`:2] == $3'b001);
    //always @(posedge S_AXI_ACLK)
    //if(~S_AXI_ARESETN)
    //    sm_pul_r <= 32'h00;
    //else if(sm_pul_wr)
    //    sm_pul_r <= S_AXI_WDATA;

        ${0}
    endmodule
endsnippet
#######################################################################计数器
snippet cnter "计数器模块" iw
reg     [${1:7}:0]        ${2}_cnt_r      ;   //计数器
wire                    $2_add_f        ;   //计数器自增条件
wire                    $2_end_f        ;   //计数器结束条件
always @(posedge sys_clk or negedge sys_reset_n)
if(~sys_reset_n)
    $2_cnt_r        <=   `!p snip.rv = int(t[1])+1`'b0;
else if($2_add_f) begin
    if($2_end_f)
        $2_cnt_r    <=   `!p snip.rv = int(t[1])+1`'b0;
    else
        $2_cnt_r    <=  $2_cnt_r + `!p snip.rv = int(t[1])+1`'b1;
end
//计数器的自增条件
assign $2_add_f = (${3});
//计数器的结束条件
assign $2_end_f = $2_add_f & ($2_cnt_r == ${0});
endsnippet
#########################################################################双口RAM存储器 地址宽度_位宽
snippet dpram "双口RAM模块" iw
/*
*   双口RAM，基于模板推导
*   `!p s0 =snip.fn.split('.')[0]; s1 = s0.split('_')[1];s2 = s0.split('_')[2];snip.rv = (2**int(s1)) *int(s2)`bits
*   `!p s0 =snip.fn.split('.')[0]; s1 = s0.split('_')[1];s2 = s0.split('_')[2];snip.rv = (2**int(s1)) *int(s2)/9216`xM9K
*/
module ${1:`!p snip.rv = snip.fn.split('.')[0]`}  //地址宽度_数据宽度 
(

    input [`!p s0 =snip.fn.split('.')[0]; s1 = s0.split('_')[2];snip.rv = int(s1)-1`:0] data_a, data_b, 
    input [`!p s0 =snip.fn.split('.')[0]; s1 = s0.split('_')[1];snip.rv = int(s1)-1`:0] addr_a, addr_b,
    input we_a, we_b, clk_a, clk_b,
    output reg [`!p s0 =snip.fn.split('.')[0]; s1 = s0.split('_')[2];snip.rv = int(s1)-1`:0] q_a, q_b
);

    reg [`!p s0 =snip.fn.split('.')[0]; s1 = s0.split('_')[2];snip.rv = int(s1)-1`:0] ram[`!p s0 =snip.fn.split('.')[0]; s1 = s0.split('_')[1]; snip.rv = 2**int(s1)-1`:0];  //

    //第一个端口
    always @ (posedge clk_a)
    begin
        // Port A 
        if (we_a) 
        begin
            ram[addr_a] <= data_a;
            q_a <= data_a;
        end
        else 
        begin
            q_a <= ram[addr_a];
        end 
    end

   //第二个端口
    always @ (posedge clk_b)
    begin
        // Port B 
        if (we_b) 
        begin
            ram[addr_b] <= data_b;
            q_b <= data_b;
        end
        else 
        begin
            q_b <= ram[addr_b];
        end 
    end

endmodule
endsnippet
#########################################################信号滤波算法
snippet sigf "对输入信号尖脉冲滤波" iw
//对${1}信号进行滤波
reg [2:0]       $1_f_r        ;
always @(posedge sys_clk or negedge sys_reset_n)
if(~sys_reset_n)
    $1_f_r     <=  3'b000;
else
    $1_f_r     <=  {$1_f_r[1:0],$1};
//如果连续两个脉冲信号没有变化，取最近一次
reg $1_last_r;
always @(posedge sys_clk or negedge sys_reset_n)
if(~sys_reset_n)
    $1_last_r    <=  1'b0;
else if($1_f_r[2] == $1_f_r[1])
    $1_last_r    <=  $1_f_r[1];
//滤波后的输出信号
wire    $1_out;
assign $1_out = ($1_f_r[2] == $1_f_r[1])? $1_f_r[1]:$1_last_r;
endsnippet
